﻿using InDepth2Demo.Model;
using System;
using System.Collections.Generic;
using System.Reflection;

namespace InDepth2Demo.Chapter3
{
    internal class ReflectionDemo_5
    {
        // typeof 
        public static void DemonstrateTypeof<X>()
        {
            Console.WriteLine(typeof(X));

            Console.WriteLine(typeof(List<>));
            Console.WriteLine(typeof(Dictionary<,>));

            Console.WriteLine(typeof(List<X>));
            Console.WriteLine(typeof(Dictionary<string, X>));

            Console.WriteLine(typeof(List<long>));  //显式封闭类型 
            Console.WriteLine(typeof(Dictionary<long, Guid>));

            // 执行结果
            //System.Int32

            //System.Collections.Generic.List`1[T]
            //System.Collections.Generic.Dictionary`2[TKey, TValue]

            //System.Collections.Generic.List`1[System.Int32]
            //System.Collections.Generic.Dictionary`2[System.String, System.Int32]

            //System.Collections.Generic.List`1[System.Int64]
            //System.Collections.Generic.Dictionary`2[System.Int64, System.Guid]

        }

        // 获取泛型和已构造Type对象的各种方式
        public static void TypeMethod()
        {
            string listTypeName = "System.Collections.Generic.List`1";
            Type defByName = Type.GetType(listTypeName);

            Type closedByName = Type.GetType(listTypeName + "[System.String]");
            Type closedByMethod = defByName.MakeGenericType(typeof(string));
            Type closedByTypeof = typeof(List<string>);

            Console.WriteLine(closedByMethod == closedByName);  // True
            Console.WriteLine(closedByName == closedByTypeof);  // True
        }

        public static void PrintTypeParameter<T>()
        {
            Console.WriteLine(typeof(T));
        }

        // 通过反射来获取和调用泛型方法
        public static void Call()
        {
            Type type = typeof(ReflectionDemo_5);  // {Name = "ReflectionDemo_5" FullName = "InDepth2Demo.Chapter3.ReflectionDemo_5"}
            MethodInfo definition = type.GetMethod("PrintTypeParameter");   // { Void PrintTypeParameter[T]() }
            MethodInfo constructed = definition.MakeGenericMethod(typeof(string));  // { Void PrintTypeParameter[String]() }
            constructed.Invoke(null, null);     // System.String

            // 用类型数组的元素 替代 当前泛型方法定义的类型参数, 并返回表示结果构造方法的 MethodInfo 对象。
            // （方法里的参数）       PrintTypeParameter<T>

            // 首先获取泛型方法定义，然后使用 MakeGenericMethod 来返回一个已构造泛型方法。
        }

        public static void Call2()
        {
            Type type = typeof(Product);

            Console.WriteLine("数据类型名:" + type.Name);
            Console.WriteLine("FullName 教据类型的完全限定名:" + type.FullName);
            Console.WriteLine("Namespace 定义数据类型的命名空间名:" + type.Namespace);
            Console.WriteLine("lsAbstract指示该类型是否是抽象类型:" + type.IsAbstract);
            Console.WriteLine("lsArray 指示该类型是否是数组:" + type.IsArray);
            Console.WriteLine("lsclass 指示该类型是否是类:" + type.IsClass);
            Console.WriteLine("IsEnum 指示该类型是否是枚举:" + type.IsEnum);
            Console.WriteLine("lsInterface 指示该类型是否是接口:" + type.IsInterface);
            Console.WriteLine("lsPublic 指示该类型是否是公有的:" + type.IsPublic);
            Console.WriteLine("lsSealed 指示该类型是否是密封类:" + type.IsSealed);
            Console.WriteLine("lsValueType 指示该类型是否是值类型:" + type.IsValueType);

            //数据类型名: Product
            //FullName 教据类型的完全限定名: InDepth2Demo.Model.Product
            //Namespace 定义数据类型的命名空间名: InDepth2Demo.Model
            //lsAbstract指示该类型是否是抽象类型:False
            //lsArray 指示该类型是否是数组: False
            //lsclass 指示该类型是否是类: True
            //IsEnum 指示该类型是否是枚举: False
            //lsInterface 指示该类型是否是接口: False
            //lsPublic 指示该类型是否是公有的: True
            //lsSealed 指示该类型是否是密封类: False
            //lsValueType 指示该类型是否是值类型: False

            object objects = Activator.CreateInstance(type);
            //得到类型实例，此步骤会得到Product类的无参构造函数。
            Console.WriteLine(objects is Product);          // True

            //// 1、取得该类构造函数信息
            //ConstructorInfo constructor = type.GetConstructor(new Type[] { typeof(Product) });
            //ConstructorInfo[] constructorInfos = type.GetConstructors();
            //Product x = new Product();
            //foreach (ConstructorInfo constructorInfo in constructorInfos)
            //{
            //    constructorInfo.Invoke(objects, null);
            //}

            //2、取得类的事件
            Console.WriteLine("---2、取得类的事件---");
            EventInfo[] eventInfo = type.GetEvents();
            foreach (EventInfo e in eventInfo)
            {
                Console.WriteLine(e.Name);
            }

            //3、获取该类字段的信息
            Console.WriteLine("---3、获取该类字段的信息---");
            FieldInfo[] fieldInfos = type.GetFields();
            foreach (FieldInfo fieldInfo in fieldInfos)
            {
                Console.WriteLine(fieldInfo.Name);
            }

            //4、获取类所有成员信息
            Console.WriteLine("---4、获取类所有成员信息---");
            MemberInfo[] info = type.GetMembers();
            foreach (MemberInfo mi in info)
            {
                Console.WriteLine(mi.Name);
            }

            //5、获取类的方法
            Console.WriteLine("---5、获取类的方法---");
            MemberInfo[] memberInfos = type.GetMethods();
            foreach (MemberInfo memberInfo in memberInfos)
            {
                Console.WriteLine(memberInfo.Name);
            }

            //6、获取类中的属性
            Console.WriteLine("---6、获取类中的属性---");
            PropertyInfo[] propertyInfos = type.GetProperties();
            foreach (PropertyInfo propertyInfo in propertyInfos)
            {
                Console.WriteLine(propertyInfo.Name);
            }

            //7、获取类实现的接口信息
            Console.WriteLine("---7、获取类实现的接口信息---");
            Type[] types = type.GetInterfaces();
            foreach (Type t in types)
            {
                Console.WriteLine(t.Name);
            }

            //9、不带参数方法调用
            type.GetMethod("PrintString", new Type[] { }).Invoke(objects, null);

            //10、带一个参数方法调用
            type.GetMethod("PrintString2", new Type[] { typeof(string) }).Invoke(objects, new object[] { "parameter" });
        }
    }
}
